package de.koller.gravity.scene.world;

import de.koller.aframe.util.ALoop;
import de.koller.aframe.util.noise.PerlinLayer;
import de.koller.aframe.util.resource.IOLoader;
import de.koller.aframe.util.search.ATile;
import de.koller.aframe.util.search.ATiledPathFinder;
import de.koller.aframe.util.search.IATileMap;
import de.koller.oceanFramework.gl.util.ImagePreview;
import de.koller.oceanFramework.gl.util.RasterManager;
import java.awt.image.BufferedImage;
import java.util.Date;
import java.util.Random;

public class Landscape {
	
	public static final int WIDTH = 1200, HEIGHT = 700;
	
	private final Random rnd = new Random();
	private final PerlinLayer heightLayer = new PerlinLayer( "height", rnd, 9, .7f );
	
	private RasterManager raster;

	public static void main( String[] args ) {
		Landscape l = new Landscape();
		BufferedImage img = l.renderFrame();
		IOLoader.savePNG( img, "./temp/landscape.png" );
		ImagePreview.showImage( img, WIDTH, HEIGHT );
	}
	
	public Landscape() {
		heightLayer.addColorRange(   0, .35, 0xff_000000, 0xff_0000ff );
		heightLayer.addColorRange( .35, .48, 0xff_0000ff, 0xff_00b2ff );
		heightLayer.addColorRange( .48, .52, 0xff_ffff00, 0xff_00ff00 );
		heightLayer.addColorRange( .52, .70, 0xff_00ff00, 0xff_009000 );
		heightLayer.addColorRange( .70,   1, 0xff_009000, 0xff_ffffff );
	}
	
	public BufferedImage renderFrame() {
		raster = new RasterManager( WIDTH, HEIGHT );
		long tstart = System.currentTimeMillis();
		
		for( int x = 0; x < WIDTH; x++ ) {
			for( int y = 0; y < HEIGHT; y++ )
				raster.setPixel( getPointColor( x, y ), x, y );
			
			long dt = System.currentTimeMillis() - tstart;
			float p = 1f / WIDTH * x;
			long tend = (long)(1f / p * dt) + tstart;
			System.out.println( (p * 100) + "% " + new Date( tend ) + 
					" (" + ((tend-System.currentTimeMillis())/1000) + " sec) " +
					ALoop.getMemory() + "MB" );
		}
		
		//for( int i = 0; i < 10; i++ ) {
		//	System.out.println( "add street " + i );
			addStreet();
		//}
		System.out.println( "ready" );
		return IOLoader.create( raster );
	}
	
	public void addStreet() {
		int[] s = new int[] { 10, 10 }; //getRandomLandPoint();
		int[] d = new int[] { 1190, 690 }; //getRandomLandPoint();
		ATile[] p = ATiledPathFinder.find( s[0], s[1], d[0], d[1], new StreetPath(), true );
		
		raster.setPixel( 0xff_000000, s[0], s[1] );
		raster.setPixel( 0xff_000000, d[0], d[1] );
		
		if( p == null )
			return;
		for( ATile t : p )
			raster.setPixel( 0xff_000000, t.posX, t.posY );
	}
	
	private int[] getRandomLandPoint() {
		int x = rnd.nextInt( WIDTH );
		int y = rnd.nextInt( HEIGHT );
		float f = landHeight( x, y );
		
		if( f < .5f )
			return getRandomLandPoint();
		else
			return new int[] { x, y };
	}
	
	private int getPointColor( float x, float y ) {
		float[] hv = frameToLandHeighCoord( x, y );
		return heightLayer.getColorAt( hv[0], hv[1] );
	}
	
	private float landHeight( float frameX, float frameY ) {
		float[] hv = frameToLandHeighCoord( frameX, frameY );
		return heightLayer.getValue( hv[0], hv[1] );
	}
	
	private float[] frameToLandHeighCoord( float x, float y ) {
		return new float[] {
			1f / HEIGHT * x * 20,
			1f / HEIGHT * y * 20 
		};
	}
	
	private class StreetPath implements IATileMap {

		@Override
		public double getWeight( ATile current, ATile successor ) {
			double d = Math.sqrt( 
				   (successor.posX - current.posX) * (successor.posX - current.posX) +
				   (successor.posY - current.posY) * (successor.posY - current.posY) );
			
			float ht = landHeight( current.posX, current.posY );
			float h = landHeight( successor.posX, successor.posY );
			
			if( ht < .5f || h < .5f ) return 10000000*d; 
			
			double hd = Math.abs( ht - h );
			return d + hd*100;
		}

		@Override
		public boolean isWayPossible( ATile current, ATile successor ) {
			if( successor.posX < 0 || successor.posX >= WIDTH ) return false;
			if( successor.posY < 0 || successor.posY >= HEIGHT ) return false;
			//float h = landHeight( successor.posX, successor.posY );

			return true;
			
//			if( h > .5f )
//				return true;
//			
//			if( current.posX == successor.posX )
//				return true;
//			if( current.posY == successor.posY )
//				return true;
//			
//			return false;
//			
		}

		@Override
		public double getHeuristic( ATile current, ATile destination ) {
			//return Math.abs( destination.posX - current.posX ) +
			//	   Math.abs( destination.posY - current.posY );
			
			return Math.sqrt( 
				   (destination.posX - current.posX) * (destination.posX - current.posX) +
				   (destination.posY - current.posY) * (destination.posY - current.posY) );
			
		}

	}
}
